﻿#region Using

using System;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;

using Common.Enums;

using GlobalServices = GameCommon.Services.Service;

#endregion

namespace Menu.Service
{
    internal static class XmlValidationService
    {
        public static bool Validate(ScreenEnum screen)
        {
            XmlSchema mainSchema;
            var path = GlobalServices.PathService.GetMenuXsd(XsdFileEnum.Main);

            using (var stream = GlobalServices.FileService.GetEmbeddedRessource(path))
            {
                mainSchema = XmlSchema.Read(stream, (sender, args) => { });
            }

            XmlSchema componentSchema;
            path = GlobalServices.PathService.GetMenuXsd(XsdFileEnum.Components);

            using (var stream = GlobalServices.FileService.GetEmbeddedRessource(path))
            {
                componentSchema = XmlSchema.Read(stream, (sender, args) => { });
                var include = new XmlSchemaInclude { Schema = componentSchema };
                mainSchema.Includes.Add(include);
            }

            LoadComponentIncludes(componentSchema, XsdFileEnum.Enumerations);

            var schemaSet = new XmlSchemaSet();
            schemaSet.Add(mainSchema);
            return Validate(screen, schemaSet);
        }

        private static void LoadComponentIncludes(XmlSchema componentSchema, XsdFileEnum xsd)
        {
            var path = GlobalServices.PathService.GetMenuXsd(xsd);

            using (var stream = GlobalServices.FileService.GetEmbeddedRessource(path))
            {
                var schema = XmlSchema.Read(stream, (sender, args) => { });
                var include = new XmlSchemaInclude { Schema = schema };
                componentSchema.Includes.Add(include);
            }
        }

        private static bool Validate(ScreenEnum screen, XmlSchemaSet schemaSet)
        {
            var path = GlobalServices.PathService.GetMenuXml(screen);

            Console.WriteLine("\r\nValidating XML file {0}...", path);

            XmlSchema compiledSchema = null;
            foreach (XmlSchema schema in schemaSet.Schemas())
            {
                compiledSchema = schema;
            }

            if (compiledSchema == null)
            {
                return false;
            }

            var result = true;
            var settings = new XmlReaderSettings();
            settings.Schemas.Add(compiledSchema);
            settings.ValidationEventHandler += (o, args) => ValidationCallBack(args, ref result);
            settings.ValidationType = ValidationType.Schema;

            var assembly = Assembly.GetExecutingAssembly();
            using (var stream = assembly.GetManifestResourceStream(path))
            {
                if (stream == null)
                {
                    return false;
                }

                using (var vreader = XmlReader.Create(stream, settings))
                {
                    while (vreader.Read())
                    {
                    }
                }
            }

            return result;
        }

        private static void ValidationCallBack(ValidationEventArgs args, ref bool result)
        {
            if (args.Severity == XmlSeverityType.Warning)
            {
                Console.WriteLine("\tWarning: Matching schema not found.  No validation occurred." + args.Message);
            }
            else
            {
                Console.WriteLine("\tValidation error: " + args.Message);
                result = false;
            }
        }
    }
}